Autor: Spinelli, Julián C.

1 Introducción

El siguiente informe pretende brindar cierta información respecto de los recorridos realizados mediante el uso de las bicicletas administradas por el Gobierno de la Ciudad de Buenos Aires, también conocidas como “ecobicis”. Para esto utilizaremos los datos publicados por el propio gobierno, realizando un recorte entre los años 2015-2021. Esto se debe a que los datos de años anteriores no se encuentran disponibles, por el momento.

2 Configuración y aproximación

En primer lugar, procedemos a cargar las librerías a utilizar:

library(tidyverse) # Set de herramientas inicial
library(lubridate) # Manejo de Fechas
library(viridis) # Escala de colores
library(plotly) # Interacción entre visualizaciones
library(kableExtra) # Visualizaciones de tablas

Luego, insertamos los dataframes correspondientes:

bicicletas_2015 <- read_csv("recorridos-realizados-2015.csv")
bicicletas_2016 <- read_csv("recorridos-realizados-2016.csv")
bicicletas_2017 <- read_csv("recorridos-realizados-2017.csv")
bicicletas_2018 <- read_csv("recorridos-realizados-2018.csv")
bicicletas_2019 <- read_csv("recorridos-realizados-2019.csv")
bicicletas_2020 <- read_csv("recorridos_realizados_2020.csv")
bicicletas_2021 <- read_csv("recorridos_realizados_2021.csv")

Primera aproximación del contenido que proveen los dataframes:

id_recorrido Duracion Recorrido fecha_origen_recorrido id_estacion_origen nombre_estacion_origen direccion_estacion_origen long_estacion_origen lat_estacion_origen fecha_destino_recorrido id_estacion_destino nombre_estacion_destino direccion_estacion_destino long_estacion_destino lat_estacion_destino id_usuario modelo_bicicleta
10758473BAEcobici 591 2021-04-10 20:38:24 UTC 2BAEcobici 002 - Retiro I Ramos Mejia, Jose Maria, Dr. Av. & Del Libertador Av. -58.37472 -34.59242 2021-04-10 20:48:15 UTC 95BAEcobici 095 - ESMERALDA ESMERALDA 516 -58.37817 -34.60211 86840BAEcobici ICONIC
10757803BAEcobici 1321 2021-04-10 16:34:08 UTC 2BAEcobici 002 - Retiro I Ramos Mejia, Jose Maria, Dr. Av. & Del Libertador Av. -58.37472 -34.59242 2021-04-10 16:56:09 UTC 73BAEcobici 073 - Ruy Díaz de Guzmán Avenida Martin Garcia y Ruy Díaz de Guzmán -58.37182 -34.63068 52860BAEcobici ICONIC
10756603BAEcobici 380 2021-04-10 07:06:00 UTC 3BAEcobici 003 - ADUANA Moreno & Av Paseo Colon -58.36826 -34.61103 2021-04-10 07:12:20 UTC 150BAEcobici 150 - RODRIGO BUENO Av. España 2200 -58.35547 -34.61875 375594BAEcobici ICONIC
10756618BAEcobici 1436 2021-04-10 07:25:08 UTC 4BAEcobici 004 - Plaza Roma Lavalle & Bouchard -58.36878 -34.60182 2021-04-10 07:49:04 UTC 353BAEcobici 237 - Madero Office 367 Sanchez De Thompson, Mariquita -58.36469 -34.59904 489972BAEcobici ICONIC
10757830BAEcobici 3736 2021-04-10 16:45:01 UTC 4BAEcobici 004 - Plaza Roma Lavalle & Bouchard -58.36878 -34.60182 2021-04-10 17:47:17 UTC 207BAEcobici 123 - BASUALDO Y RODO Basualdo 1218 -58.49263 -34.64932 77965BAEcobici ICONIC
10757832BAEcobici 3681 2021-04-10 16:45:11 UTC 4BAEcobici 004 - Plaza Roma Lavalle & Bouchard -58.36878 -34.60182 2021-04-10 17:46:32 UTC 207BAEcobici 123 - BASUALDO Y RODO Basualdo 1218 -58.49263 -34.64932 764009BAEcobici ICONIC

3 Manipulación y limpieza de los datos

A continuación procedemos a recopilar la información que utilizaremos de los distintos dataframes y realizar una limpieza y normalización de los mismos:

glimpse(bicicletas_2015)
## Rows: 503,252
## Columns: 15
## $ periodo                    <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2…
## $ genero_usuario             <chr> "M", "F", "M", "M", "M", "F", "M", "F", "M"…
## $ fecha_origen_recorrido     <dttm> 2015-05-01 00:00:18, 2015-05-01 00:02:06, …
## $ id_estacion_origen         <dbl> 25, 17, 17, 29, 29, 1, 30, 1, 4, 36, 18, 28…
## $ nombre_estacion_origen     <chr> "Plaza Güemes", "Plaza Almagro", "Plaza Alm…
## $ long_estacion_origen       <dbl> -58.41607, -58.41883, -58.41883, -58.43458,…
## $ lat_estacion_origen        <dbl> -34.58952, -34.60640, -34.60640, -34.60846,…
## $ domicilio_estacion_origen  <chr> "Salguero Jerónimo y Mansilla", "Plaza Alma…
## $ duracion_recorrido         <chr> "0 days 00:26:24.000000000", "0 days 00:57:…
## $ fecha_destino_recorrido    <dttm> 2015-05-01 00:26:42, 2015-05-01 00:59:59, …
## $ id_estacion_destino        <dbl> 29, 25, 25, 25, 25, 25, 30, 25, 18, 7, 9, 2…
## $ nombre_estacion_destino    <chr> "Parque Centenario", "Plaza Güemes", "Plaza…
## $ long_estacion_destino      <dbl> -58.43458, -58.41607, -58.41607, -58.41607,…
## $ lat_estacion_destino       <dbl> -34.60846, -34.58952, -34.58952, -34.58952,…
## $ domicilio_estacion_destino <chr> "Patricias Argentinas y Carlos Finlay", "Sa…
glimpse(bicicletas_2017)
## Rows: 1,048,158
## Columns: 15
## $ periodo                    <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
## $ genero_usuario             <chr> "M", "M", "M", "M", "M", "F", "M", "M", "F"…
## $ fecha_origen_recorrido     <dttm> 2017-01-01 00:02:14, 2017-01-01 00:02:59, …
## $ id_estacion_origen         <dbl> 60, 79, 11, 79, 150, 79, 85, 48, 26, 79, 24…
## $ nombre_estacion_origen     <chr> "25 de Mayo", "Azucena Villaflor", "Tribuna…
## $ long_estacion_origen       <dbl> -58.37116, -58.36397, -58.38502, -58.36397,…
## $ lat_estacion_origen        <dbl> -34.60164, -34.61172, -34.60131, -34.61172,…
## $ domicilio_estacion_origen  <chr> "25 de Mayo y Lavalle", "Azucena Villaflor …
## $ duracion_recorrido         <chr> "0 days 00:27:44.000000000", "0 days 01:57:…
## $ fecha_destino_recorrido    <dttm> 2017-01-01 00:28:38, 2017-01-01 01:00:52, …
## $ id_estacion_destino        <dbl> 4, 54, 84, 74, 1, 74, 20, 96, 68, 17, 79, 4…
## $ nombre_estacion_destino    <chr> "Plaza Roma", "Acuña de Figueroa", "Lavalle…
## $ long_estacion_destino      <dbl> -58.36895, -58.42170, -58.39547, -58.43424,…
## $ lat_estacion_destino       <dbl> -34.60172, -34.59822, -34.60229, -34.60457,…
## $ domicilio_estacion_destino <chr> "Lavalle y Bouchard", "Lavalle y Acuña de F…
glimpse(bicicletas_2021)
## Rows: 2,649,845
## Columns: 16
## $ id_recorrido               <chr> "10758473BAEcobici", "10757803BAEcobici", "…
## $ `Duracion Recorrido`       <dbl> 591, 1321, 380, 1436, 3736, 3681, 3713, 250…
## $ fecha_origen_recorrido     <chr> "2021-04-10 20:38:24 UTC", "2021-04-10 16:3…
## $ id_estacion_origen         <chr> "2BAEcobici", "2BAEcobici", "3BAEcobici", "…
## $ nombre_estacion_origen     <chr> "002 - Retiro I", "002 - Retiro I", "003 - …
## $ direccion_estacion_origen  <chr> "Ramos Mejia, Jose Maria, Dr. Av. & Del Lib…
## $ long_estacion_origen       <dbl> -58.37472, -58.37472, -58.36826, -58.36878,…
## $ lat_estacion_origen        <dbl> -34.59242, -34.59242, -34.61103, -34.60182,…
## $ fecha_destino_recorrido    <chr> "2021-04-10 20:48:15 UTC", "2021-04-10 16:5…
## $ id_estacion_destino        <chr> "95BAEcobici", "73BAEcobici", "150BAEcobici…
## $ nombre_estacion_destino    <chr> "095 - ESMERALDA", "073 - Ruy Díaz de Guzmá…
## $ direccion_estacion_destino <chr> "ESMERALDA 516", "Avenida Martin Garcia y R…
## $ long_estacion_destino      <dbl> -58.37817, -58.37182, -58.35547, -58.36469,…
## $ lat_estacion_destino       <dbl> -34.60211, -34.63068, -34.61875, -34.59904,…
## $ id_usuario                 <chr> "86840BAEcobici", "52860BAEcobici", "375594…
## $ modelo_bicicleta           <chr> "ICONIC", "ICONIC", "ICONIC", "ICONIC", "IC…

Lo primero que surge de esta breve exploración es que, en los distintos sets, conviven mismas variables con distintos tipos de datos (id_estacion_origen; id_estacion_destino; fecha_origen_recorrido; fecha_destino_recorrido; duracion_recorrido). Si observamos detenidamente, algunos se encuentran representados como characters, mientras que entros frames, aparecen como datetime. Con lo cual, lo primero que debemos hacer es homogeneizar estos tipos de datos, para luego no tener un error al momento de recopilar los data sets.

bicicletas_2015 <- bicicletas_2015 %>%
  mutate(id_estacion_origen = as.character(id_estacion_origen))%>%
  mutate(id_estacion_destino = as.character(id_estacion_destino))%>%
  mutate(fecha_origen_recorrido = ymd_hms(fecha_origen_recorrido)) %>%
  mutate(fecha_destino_recorrido = ymd_hms(fecha_destino_recorrido))

bicicletas_2016 <- bicicletas_2016 %>%
  mutate(id_estacion_origen = as.character(id_estacion_origen))%>%
  mutate(id_estacion_destino = as.character(id_estacion_destino))%>%
  mutate(fecha_origen_recorrido = ymd_hms(fecha_origen_recorrido)) %>%
  mutate(fecha_destino_recorrido = ymd_hms(fecha_destino_recorrido))

bicicletas_2017 <- bicicletas_2017 %>%
  mutate(id_estacion_origen = as.character(id_estacion_origen))%>%
  mutate(id_estacion_destino = as.character(id_estacion_destino))
  

bicicletas_2018 <- bicicletas_2018 %>%
  mutate(id_estacion_origen = as.character(id_estacion_origen))%>%
  mutate(id_usuario = as.character(id_usuario))%>%
  mutate(id_estacion_destino = as.character(id_estacion_destino))

bicicletas_2019 <-bicicletas_2019 %>%
   mutate(fecha_origen_recorrido = ymd_hms(fecha_origen_recorrido)) %>%
   mutate(fecha_destino_recorrido = ymd_hms(fecha_destino_recorrido))%>%
   mutate(duracion_recorrido = as.character(duracion_recorrido))

bicicletas_2020 <-bicicletas_2020 %>%
  mutate(fecha_origen_recorrido = ymd_hms(fecha_origen_recorrido)) %>%
  mutate(fecha_destino_recorrido = ymd_hms(fecha_destino_recorrido))%>%
  mutate(duracion_recorrido = as.character(duracion_recorrido))  

bicicletas_2021 <-bicicletas_2021 %>%
  mutate(fecha_origen_recorrido = ymd_hms(fecha_origen_recorrido)) %>%
  mutate(fecha_destino_recorrido = ymd_hms(fecha_destino_recorrido))%>%
  mutate(duracion_recorrido = as.character(`Duracion Recorrido`))%>%
  select(-`Duracion Recorrido`)

Una vez realizado este proceso, procedemos a construir un solo dataframe que contenga las variables desde el 2015 hasta el 2021:

bicicletas_2015_2021 <- bind_rows(bicicletas_2015,bicicletas_2016,bicicletas_2017,bicicletas_2018,bicicletas_2019,bicicletas_2020,bicicletas_2021)

Ya con el dataframe contenedor creado, removemos los dataframes que no utilizaremos, manteniendo únicamente el que corresponde al 2015-2021:

rm(bicicletas_2015, bicicletas_2016, bicicletas_2017,bicicletas_2018,bicicletas_2019,bicicletas_2020,bicicletas_2021)

Aqui nos encargamos de limpiar los datos de la variable “Duración Recorrido” en el dataframe, dado que contiene una multiplicidad de caracteres variados. Utilizando la función clean_names() de la libreria janitor nos encargaremos de estandarizar los datos de dicha variable:

bicicletas_2015_2021_cleaned <- bicicletas_2015_2021 %>% 
  janitor::clean_names()
periodo genero_usuario fecha_origen_recorrido id_estacion_origen nombre_estacion_origen long_estacion_origen lat_estacion_origen domicilio_estacion_origen duracion_recorrido fecha_destino_recorrido id_estacion_destino nombre_estacion_destino long_estacion_destino lat_estacion_destino domicilio_estacion_destino id_usuario id_recorrido direccion_estacion_origen direccion_estacion_destino modelo_bicicleta
2015 M 2015-05-01 00:00:18 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla 0 days 00:26:24.000000000 2015-05-01 00:26:42 29 Parque Centenario -58.43458 -34.60846 Patricias Argentinas y Carlos Finlay NA NA NA NA NA
2015 F 2015-05-01 00:02:06 17 Plaza Almagro -58.41883 -34.60640 Plaza Almagro 0 days 00:57:53.000000000 2015-05-01 00:59:59 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla NA NA NA NA NA
2015 M 2015-05-01 00:02:53 17 Plaza Almagro -58.41883 -34.60640 Plaza Almagro 0 days 01:03:08.000000000 2015-05-01 01:06:01 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla NA NA NA NA NA
2015 M 2015-05-01 00:08:01 29 Parque Centenario -58.43458 -34.60846 Patricias Argentinas y Carlos Finlay 0 days 01:04:18.000000000 2015-05-01 01:12:19 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla NA NA NA NA NA
2015 M 2015-05-01 00:08:57 29 Parque Centenario -58.43458 -34.60846 Patricias Argentinas y Carlos Finlay 0 days 01:09:41.000000000 2015-05-01 01:18:38 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla NA NA NA NA NA
2015 F 2015-05-01 00:09:06 1 Facultad de Derecho -58.39245 -34.58313 Av. Pres.Figueroa Alcorta y Juan A.Bibiloni 0 days 01:21:27.000000000 2015-05-01 01:30:33 25 Plaza Güemes -58.41607 -34.58952 Salguero Jerónimo y Mansilla NA NA NA NA NA

Por ultimo, procedemos a remover bicicletas_2015_2021:

rm(bicicletas_2015_2021)

4 Cual es la estación mas demandada?

Como primer paso, verificamos cuál es la estación con mayor demanda de bicicletas :

Estacion_mayor_demanda <- bicicletas_2015_2021_cleaned %>% 
  count(nombre_estacion_origen,
        sort = T,
        name = 'cantidad_salidas')%>% 
  top_n(10)
nombre_estacion_origen cantidad_salidas
147 - Constitución 137918
014 - Pacifico 127443
029 - Parque Centenario 108068
Parque Las Heras 107270
160 - Godoy Cruz y Libertador 95172
009 - Parque Las Heras 94408

Lo que devuelve esta operación es que la estación 147 - Constitución es la más demandada durante este periodo. En consecuencia, trabajaremos con ella de ahora en adelante.

5 ¿Hacia dónde se dirige la gente desde esa estación?

Lo primero que debemos realizar es una reducción de los datos para recibir únicamente las salidas de la estación 147 - Constitución . Luego, filtraremos también para que el lugar de devolución de la bicicleta no sea la estación desde donde se retiró la misma. Una vez realizado este proceso, usaremos la función count() para verificar la frecuencia de la variable categórica nombre_estacion_destino.

destinos_desde_constitucion <- bicicletas_2015_2021_cleaned %>% 
  filter(nombre_estacion_origen == '147 - Constitución' &
           nombre_estacion_destino != '147 - Constitución') %>% 
  count(nombre_estacion_destino,
        sort = T,
        name = 'cantidad_salidas_desde_constitucion') 

Al generar nuestra primera visualización utilizaremos los primeros diez valores para que el gráfico sea interpretable:

destinos_desde_constitucion %>% 
  top_n(10, cantidad_salidas_desde_constitucion) %>% 
  ggplot(aes(x=reorder(nombre_estacion_destino,
                       cantidad_salidas_desde_constitucion),
             weight=cantidad_salidas_desde_constitucion))+
  geom_bar(aes(fill = factor(nombre_estacion_destino))) +
  scale_fill_viridis(discrete = T) +
  theme_minimal() +
  theme(legend.position = "none") +
  coord_flip() +
  labs(x = 'Estación',
       y = 'Cantidad de llegadas',
       title = 'Cantidad de llegadas por estación',
       subtitle = 'desde Constitución',
       caption = 'Fuente de datos: https://data.buenosaires.gob.ar/')

6 ¿Cómo evolucionó el uso durante los años para esa estación de bicicletas?

En primer lugar, vamos a crear un pequeño dataframe con los datos discriminados de nuestra estación. Esto es, los viajes salidos desde la estación constitución y que no volvieron a la estación como destino.

bicicletas_2015_2021_constitucion<-bicicletas_2015_2021_cleaned %>% 
  filter(nombre_estacion_origen == '147 - Constitución' | nombre_estacion_origen == 'Constitución',
         nombre_estacion_destino != nombre_estacion_origen)

Luego modificamos fecha_origen_recorrido para que se visualice la fecha sin horario mediante as_date() . Finalmente, implementamos la función un count() para calcular la frecuencia de cada fecha.

viajes_desde_constitucion_fecha <- bicicletas_2015_2021_constitucion %>%
  mutate(fecha_de_inicio = parse_date_time(fecha_origen_recorrido, 'ymd HMS'),
         dia_inicio = as_date(fecha_de_inicio)) %>%
  count(dia_inicio) 
visualizacion_viajes_por_fecha <- viajes_desde_constitucion_fecha %>% 
  ggplot(aes(x=dia_inicio, y = n)) + 
  geom_line(color = 'green3', size = 1.5)+
  theme_minimal() +
  theme(legend.position = "none") +
  labs(x = 'Dia',
       y = 'Cantidad de salidas',
       title = 'Cantidad de salidas por día desde Constitución')

ggplotly(visualizacion_viajes_por_fecha, tooltip = c("x", "y"))

La información que nos ha devuelto esta visualización resulta interesante. Si observamos el gráfico, previo al 2019 no hay datos respecto de la estación 147 - Constitución .

7 ¿Qué día de la semana se utilizó más la estación?

Para continuar, nos proponemos verificar qué día de la semana fue el más demandado en nuestro recorte temporal.

Primero, crearemos una variables que nos permita distinguir los días de la semana en nuestra variable dia_inicio.

viajes_desde_constitucion_fecha$dia_semana_salida <- weekdays(viajes_desde_constitucion_fecha$dia_inicio) 

Con esta información, vamos a sumar la cantidad de salidas por fechas, pero agrupada según los días de la semana. Luego, la ordenaremos para verificar que día se dió la mayor cantidad de retiros.

viajes_desde_constitucion_semana <- viajes_desde_constitucion_fecha %>% 
  group_by(dia_semana_salida) %>% 
  summarise(Cantidad_salidas_por_dia = sum(n)) %>% 
  arrange(desc(Cantidad_salidas_por_dia))

Por último, realizamos la visualización de los mismos en un gráfico de barras, ordenado por los días de la semana:

visualización_viajes_constitucion_semana <-viajes_desde_constitucion_semana %>% 
ggplot(aes(x= fct_relevel(
    dia_semana_salida,
    "lunes",
    "martes",
    "miércoles",
    "jueves",
    "viernes",
    "sábado",
    "domingo"
  ), y=Cantidad_salidas_por_dia, fill = dia_semana_salida, label = Cantidad_salidas_por_dia)) + 
  geom_bar(stat = "identity")+
  geom_text(size = 3, 
            position = position_stack(vjust = 0.5), 
            colour = 'white') + 
  labs(x = '',
       y = '',
       title = 'Cantidad de salidas por día de la semana',
       subtitle = 'desde Constitución (2019-2021)',
       caption = 'Fuente de datos: https://data.buenosaires.gob.ar/') +
  theme(legend.position = "none")

Como podemos observar, el día Miercoles fue el día que más salidas hubo desde la estación 147 - Constitución con un total de 22881 salidas en el periodo 2019-2021.

8 ¿A qué hora crece la demanda?

Para finalizar, nos proponemos observar qué hora del día es la más demandada para la estación.

En primer lugar, crearemos dos variables que nos permiten separar la fecha del retiro de la bicicleta del horario en el que se produjo su retiro:

bicicletas_2015_2021_constitucion$dia_inicio <- as.Date(bicicletas_2015_2021_constitucion$fecha_origen_recorrido)  
bicicletas_2015_2021_constitucion$hora_inicio <- format(as.POSIXct(bicicletas_2015_2021_constitucion$fecha_origen_recorrido) , format = "%H")

Una vez realizado este proceso, construimos un pequeño dataframe que contabilice la cantidad de salidas por hora:

viajes_desde_constitucion_hora <- bicicletas_2015_2021_constitucion %>% 
  count(hora_inicio,
        sort = T,
        name = 'cantidad_salidas_hora')

Por último, generamos la visualización de los datos obtenidos:

visualizacion_viajes_por_hora <-viajes_desde_constitucion_hora %>% 
ggplot(aes(x= hora_inicio, y=cantidad_salidas_hora, fill = cantidad_salidas_hora, label = cantidad_salidas_hora, width= .8)) + 
  geom_bar(stat = "identity",width= 2)+
  geom_text(size = 3, 
            position = position_stack(vjust = 0.5), 
            colour = 'white') + 
  coord_flip() +
  labs(x = 'Hora',
       y = 'Cantidad',
       title = 'Cantidad de salidas por hora',
       subtitle = 'desde Constitución (2019-2021)',
       caption = 'Fuente de datos: https://data.buenosaires.gob.ar/') +
  theme(legend.position = "none")

Como podemos observar, las 18hs aparece como la más demandada, con un total de 11585 retiros en nuestro recorte temporal.